def vm_get_memory_dynamic_max(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_todo()
+ return xen_api_success(dom.get_memory_dynamic_max())
def vm_get_memory_dynamic_min(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_todo()
+ return xen_api_success(dom.get_memory_dynamic_min())
def vm_get_VCPUs_policy(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
def vm_get_builder(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_todo()
+ return xen_api_success(dom.get_builder())
def vm_get_boot_method(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
- return xen_api_success('')
+ return xen_api_success(dom.get_boot_method())
def vm_get_kernel_kernel(self, session, vm_ref):
dom = XendDomain.instance().get_vm_by_uuid(vm_ref)
'resident_on': XendNode.instance().uuid,
'memory_static_min': xeninfo.get_memory_static_min(),
'memory_static_max': xeninfo.get_memory_static_max(),
- 'memory_dynamic_min': xeninfo.get_memory_static_min(),
- 'memory_dynamic_max': xeninfo.get_memory_static_max(),
+ 'memory_dynamic_min': xeninfo.get_memory_dynamic_min(),
+ 'memory_dynamic_max': xeninfo.get_memory_dynamic_max(),
'memory_actual': xeninfo.get_memory_static_min(),
'vcpus_policy': xeninfo.get_vcpus_policy(),
'vcpus_params': xeninfo.get_vcpus_params(),
from xen.xend import balloon, sxp
from xen.xend.XendError import XendError, VmError
from xen.xend.XendLogging import log
-from xen.xend.XendConstants import *
from xen.xend.XendConfig import XendConfig
+from xen.xend.XendConstants import *
SIGNATURE = "LinuxGuestRecord"
XC_SAVE = "xc_save"
vmconfig = p.get_val()
if dominfo:
- dominfo.update(XendConfig(sxp = vmconfig), refresh = False)
+ dominfo.update(XendConfig(sxp_obj = vmconfig), refresh = False)
dominfo.resume()
else:
dominfo = xd.restore_(vmconfig)
XendConfig API
XendConfig will try to mirror as closely the Xen API VM Struct
- providing a backwards compatibility mode for SXP dumping, loading.
+ with extra parameters for those options that are not supported.
"""
+def reverse_dict(adict):
+ """Return the reverse mapping of a dictionary."""
+ return dict([(v, k) for k, v in adict.items()])
-LEGACY_CFG_TO_XENAPI_CFG = {
+# Mapping from XendConfig configuration keys to the old
+# legacy configuration keys that map directly.
+
+XENAPI_CFG_TO_LEGACY_CFG = {
'uuid': 'uuid',
- 'vcpus': 'vcpus_number',
- 'maxmem': 'memory_static_max',
- 'memory': 'memory_static_min',
- 'name': 'name_label',
- 'on_poweroff': 'actions_after_shutdown',
- 'on_reboot': 'actions_after_reboot',
- 'on_crash': 'actions_after_crash',
- 'bootloader': 'boot_method',
- 'kernel_kernel': 'kernel_kernel',
- 'kernel_initrd': 'kernel_initrd',
- 'kernel_args': 'kernel_args',
- }
-
-XENAPI_CFG_CUSTOM_TRANSLATE = [
- 'vifs',
- 'vbds',
- ]
+ 'vcpus_number': 'vcpus',
+ 'memory_static_min': 'memory',
+ 'memory_static_max': 'maxmem',
+ 'name_label': 'name',
+ 'actions_after_shutdown': 'on_poweroff',
+ 'actions_after_reboot': 'on_reboot',
+ 'actions_after_crash': 'on_crash',
+ 'platform_localtime': 'localtime',
+}
+LEGACY_CFG_TO_XENAPI_CFG = reverse_dict(XENAPI_CFG_TO_LEGACY_CFG)
+
+# Mapping from XendConfig configuration keys to the old
+# legacy configuration keys that are found in the 'image'
+# SXP object.
XENAPI_HVM_CFG = {
'platform_std_vga': 'std-vga',
'platform_serial' : 'serial',
'platform_keymap' : 'keymap',
}
-XENAPI_UNSUPPORTED_IN_LEGACY_CFG = [
+# List of XendConfig configuration keys that have no equivalent
+# in the old world.
+
+XENAPI_UNSUPPORTED_BY_LEGACY_CFG = [
'name_description',
'user_version',
'is_a_template',
'platform_clock_offset',
'platform_enable_audio',
'platform_keymap',
+ 'boot_method',
'builder',
'grub_cmdline',
'pci_bus',
'otherconfig'
- ]
+]
+
+# List of legacy configuration keys that have no equivalent in the
+# Xen API, but are still stored in XendConfig.
+
+LEGACY_UNSUPPORTED_BY_XENAPI_CFG = [
+ # roundtripped (dynamic, unmodified)
+ 'shadow_memory',
+ 'security',
+ 'vcpu_avail',
+ 'cpu_weight',
+ 'cpu_cap',
+ 'bootloader',
+ 'bootloader_args',
+ 'features',
+ # read/write
+ 'on_xend_start',
+ 'on_xend_stop',
+ # read-only
+ 'domid',
+ 'start_time',
+ 'cpu_time',
+ 'online_vcpus',
+ # write-once
+ 'cpu',
+ 'cpus',
+]
+
+LEGACY_CFG_TYPES = {
+ 'uuid': str,
+ 'name': str,
+ 'vcpus': int,
+ 'vcpu_avail': int,
+ 'memory': int,
+ 'shadow_memory': int,
+ 'maxmem': int,
+ 'start_time': float,
+ 'cpu_cap': int,
+ 'cpu_weight': int,
+ 'cpu_time': float,
+ 'bootloader': str,
+ 'bootloader_args': str,
+ 'features': str,
+ 'localtime': int,
+ 'name': str,
+ 'on_poweroff': str,
+ 'on_reboot': str,
+ 'on_crash': str,
+ 'on_xend_stop': str,
+ 'on_xend_start': str,
+}
+
+# Values that should be stored in xenstore's /vm/<uuid> that is used
+# by Xend. Used in XendDomainInfo to restore running VM state from
+# xenstore.
+LEGACY_XENSTORE_VM_PARAMS = [
+ 'uuid',
+ 'name',
+ 'vcpus',
+ 'vcpu_avail',
+ 'memory',
+ 'shadow_memory',
+ 'maxmem',
+ 'start_time',
+ 'name',
+ 'on_poweroff',
+ 'on_crash',
+ 'on_reboot',
+ 'on_xend_start',
+ 'on_xend_stop',
+]
+
+LEGACY_IMAGE_CFG = [
+ ('root', str),
+ ('ip', str),
+ ('nographic', int),
+ ('vnc', int),
+ ('sdl', int),
+ ('vncdisplay', int),
+ ('vncunused', int),
+]
+
+LEGACY_IMAGE_HVM_CFG = [
+ ('device_model', str),
+ ('display', str),
+ ('xauthority', str),
+ ('vncconsole', int),
+ ('pae', int),
+ ('apic', int),
+ ('acpi', int),
+ ('serial', str),
+]
+
+LEGACY_IMAGE_HVM_DEVICES_CFG = [
+ ('boot', str),
+ ('fda', str),
+ ('fdb', str),
+ ('soundhw', str),
+ ('isa', str),
+ ('vcpus', int),
+ ('acpi', int),
+ ('usb', str),
+ ('usbdevice', str),
+]
+
# configuration params that need to be converted to ints
'memory_static_max',
'memory_dynamic_min',
'memory_dynamic_max',
+ 'memory_actual',
'tpm_instance',
'tpm_backend',
]
-##
-## Xend Configuration Parameters
-##
-
-
-# All parameters of VMs that may be configured on-the-fly, or at start-up.
-VM_CONFIG_ENTRIES = [
- ('name', str),
- ('on_crash', str),
- ('on_poweroff', str),
- ('on_reboot', str),
- ('on_xend_start', str),
- ('on_xend_stop', str),
-]
-
-# All entries written to the store. This is VM_CONFIG_ENTRIES, plus those
-# entries written to the store that cannot be reconfigured on-the-fly.
-VM_STORE_ENTRIES = [
- ('uuid', str),
- ('vcpus', int),
- ('vcpu_avail', int),
- ('memory', int),
- ('maxmem', int),
- ('start_time', float),
-]
-
-VM_STORED_ENTRIES = VM_CONFIG_ENTRIES + VM_STORE_ENTRIES
-
-# Configuration entries that we expect to round-trip -- be read from the
-# config file or xc, written to save-files (i.e. through sxpr), and reused as
-# config on restart or restore, all without munging. Some configuration
-# entries are munged for backwards compatibility reasons, or because they
-# don't come out of xc in the same form as they are specified in the config
-# file, so those are handled separately.
-
-ROUNDTRIPPING_CONFIG_ENTRIES = [
- ('uuid', str),
- ('vcpus', int),
- ('vcpu_avail', int),
- ('cpu_cap', int),
- ('cpu_weight', int),
- ('memory', int),
- ('shadow_memory', int),
- ('maxmem', int),
- ('bootloader', str),
- ('bootloader_args', str),
- ('features', str),
- ('localtime', int),
-]
-ROUNDTRIPPING_CONFIG_ENTRIES += VM_CONFIG_ENTRIES
-
-## Static Configuration
-
-STATIC_CONFIG_ENTRIES = [
- ('cpu', int),
- ('cpus', str),
- ('image', list),
- ('security', list), # TODO: what if null?
-]
-
-DEPRECATED_ENTRIES = [
- ('restart', str),
-]
-
##
## Config Choices
##
CONFIG_OLD_DOM_STATES = ('running', 'blocked', 'paused', 'shutdown',
'crashed', 'dying')
-##
-## Defaults
-##
-
-def DEFAULT_VCPUS(info):
- if 'max_vcpu_id' in info: return int(info['max_vcpu_id']) + 1
- else: return 1
-
-DEFAULT_CONFIGURATION = (
- ('uuid', lambda info: uuid.createString()),
- ('name', lambda info: 'Domain-' + info['uuid']),
-
- ('on_poweroff', lambda info: 'destroy'),
- ('on_reboot', lambda info: 'restart'),
- ('on_crash', lambda info: 'restart'),
- ('features', lambda info: ''),
-
-
- ('memory', lambda info: 0),
- ('shadow_memory',lambda info: 0),
- ('maxmem', lambda info: 0),
- ('bootloader', lambda info: None),
- ('bootloader_args', lambda info: None),
- ('backend', lambda info: []),
- ('device', lambda info: {}),
- ('image', lambda info: None),
- ('security', lambda info: []),
- ('on_xend_start', lambda info: 'ignore'),
- ('on_xend_stop', lambda info: 'ignore'),
-
- ('cpus', lambda info: []),
- ('cpu_cap', lambda info: 0),
- ('cpu_weight', lambda info: 256),
- ('vcpus', lambda info: DEFAULT_VCPUS(info)),
- ('online_vcpus', lambda info: info['vcpus']),
- ('max_vcpu_id', lambda info: info['vcpus']-1),
- ('vcpu_avail', lambda info: (1<<info['vcpus'])-1),
-
- # New for Xen API
- ('kernel_kernel', lambda info: ''),
- ('kernel_initrd', lambda info: ''),
- ('kernel_args', lambda info: ''),
-
-)
-
class XendConfigError(VmError):
def __str__(self):
return 'Invalid Configuration: %s' % str(self.value)
-##
-## XendConfig SXP Config Compat
-##
-
-class XendSXPConfig:
- def get_domid(self):
- pass
- def get_handle(self):
- return self['uuid']
-
-
##
## XendConfig Class (an extended dictionary)
##
class XendConfig(dict):
- """ Generic Configuration Parser accepting SXP, Python or XML.
- This is a dictionary-like object that is populated.
+ """ The new Xend VM Configuration.
- @ivar legacy: dictionary holding legacy xen domain info
- @ivar xenapi: dictionary holding xen api config info
+ Stores the configuration in xenapi compatible format but retains
+ import and export functions for SXP.
"""
-
- def __init__(self, filename = None, fd = None,
- sxp = None, xml = None, pycfg = None, xenapi_vm = None,
- cfg = {}):
- """Constructor. Provide either the filename, fd or sxp.
-
- @keyword filename: filename of an SXP file
- @keyword fd: file descriptor of an SXP file
- @keyword sxp: a list of list of a parsed SXP
- @keyword xml: an XML tree object
- @keyword xenapi_vm: a struct passed from an XMLRPC call (Xen API)
- @keyword cfg: a dictionary of configuration (eg. from xc)
- """
- format = 'unknown'
-
- self.xenapi = {}
-
- if filename and not fd:
- fd = open(filename, 'r')
-
- if fd:
- format = self._detect_format(fd)
+ def __init__(self, filename = None, sxp_obj = None,
+ xapi = None, dominfo = None):
- if fd:
- if format == 'sxp':
- sxp = self._read_sxp(fd)
- elif format == 'python' and filename != None:
- pycfg = self._read_python(filename)
- elif format == 'python' and filename == None:
- raise XendConfigError("Python files must be passed as a "
- "filename rather than file descriptor.")
- elif format == 'xml':
- xml = self._read_xml(fd)
- else:
- raise XendConfigError("Unable to determine format of file")
-
- if sxp:
- cfg = self._populate_from_sxp(sxp)
- if xml:
- cfg = self._populate_from_xml(xml)
- if pycfg:
- cfg = self._populate_from_python_config(pycfg)
- if xenapi_vm:
- cfg = self._populate_from_xenapi_vm(xenapi_vm)
-
- if cfg:
- self.update(cfg)
-
- if xenapi_vm:
- self.xenapi.update(xenapi_vm)
-
- log.debug('XendConfig: %s' % str(self))
- self.validate()
-
- #
- # Xen API Attribute Access
- #
+ dict.__init__(self)
+ self.update(self._defaults())
- def __getattr__(self, name):
- try:
- return dict.__getattr__(self, name)
- except AttributeError:
+ if filename:
try:
- return self.__dict__['xenapi'][name]
- except KeyError:
- raise AttributeError("XendConfig Xen API has no attribute "
- "'%s'" % name)
-
-
- def __setattr__(self, name, value):
- try:
- return dict.__setattr__(self, name, value)
- except AttributeError:
- self.xenapi[name] = value
- #self.set_legacy_api_with_xen_api_value(name, value)
-
- def __delattr__(self, name):
- try:
- dict.__delattr__(self, name)
- except AttributeError:
- del self.xenapi[name]
- #self.del_legacy_api_with_xen_api_key(name)
-
-
- """
- #
- # Legacy API Attribute Access
- #
-
- def __getitem__(self, key):
- try:
- return self.legacy[key]
- except KeyError:
- raise AttributeError, "XendConfig Legacy has no attribute '%s'"\
- % key
-
- def __setitem__(self, key, value):
- self.legacy[key] = value
- self.set_xen_api_with_legacy_api_value(key, value)
-
- def __delitem__(self, key):
- del self.legacy[key]
- self.del_xen_api_with_legacy_api_key(key)
- """
-
-
- def _detect_format(self, fd):
- """Detect the format of the configuration passed.
-
- @param fd: file descriptor of contents to detect
- @rtype: string, 'sxp', 'xml', 'python' or 'unknown'
- """
- format = 'unknown'
+ sxp_obj = sxp.parse(open(filename,'r'))
+ sxp_obj = sxp_obj[0]
+ except IOError, e:
+ raise XendConfigError("Unable to read file: %s" % filename)
- fd.seek(0)
- for line in fd:
- stripped = line.strip()
- if stripped:
- if re.search(r'^\(', stripped):
- format = 'sxp'
- elif re.search(r'^\<?xml', stripped):
- format = 'xml'
- else:
- format = 'python'
- break
-
- fd.seek(0)
- return format
-
- def _read_sxp(self, fd):
- """ Read and parse SXP (from SXP to list of lists)
-
- @rtype: list of lists.
- """
- try:
- parsed = sxp.parse(fd)[0]
- return parsed
- except:
- raise
- return None
-
- def _read_xml(self, fd):
- """TODO: Read and parse XML (from XML to dict)
-
- @rtype: dict
- """
- raise NotImplementedError
-
- def _read_python(self, filename):
- """Read and parse python module that represents the config.
+ if sxp_obj:
+ self._sxp_to_xapi(sxp_obj)
+ self._sxp_to_xapi_unsupported(sxp_obj)
+ elif xapi:
+ self.update(xapi)
+ self._add_xapi_unsupported()
+ elif dominfo:
+ # output from xc.domain_getinfo
+ self._dominfo_to_xapi(dominfo)
+
+ log.debug('XendConfig.init: %s' % self)
+
+ # validators go here
+ self.validate()
- @rtype: dict
- """
- cfg_globals = {}
- execfile(filename, cfg_globals, {})
- return cfg_globals
+ def _defaults(self):
+ defaults = {
+ 'uuid': uuid.createString(),
+ 'name_label': 'Domain-Unnamed',
+ 'actions_after_shutdown': 'destroy',
+ 'actions_after_reboot': 'restart',
+ 'actions_after_crash': 'restart',
+ 'actions_after_suspend': '',
+ 'features': '',
+ 'builder': 'linux',
+ 'memory_static_min': 0,
+ 'memory_dynamic_min': 0,
+ 'shadow_memory': 0,
+ 'memory_static_max': 0,
+ 'memory_dynamic_max': 0,
+ 'memory_actual': 0,
+ 'boot_method': None,
+ 'bootloader': None,
+ 'bootloader_args': None,
+ 'devices': {},
+ 'image': {},
+ 'security': None,
+ 'on_xend_start': 'ignore',
+ 'on_xend_stop': 'ignore',
+ 'cpus': [],
+ 'cpu_weight': 256,
+ 'cpu_cap': 0,
+ 'vcpus_number': 1,
+ 'online_vcpus': 1,
+ 'max_vcpu_id': 0,
+ 'vcpu_avail': 1,
+ 'vif_refs': [],
+ 'vbd_refs': [],
+ 'vtpm_refs': [],
+ }
+
+ defaults['name_label'] = 'Domain-' + defaults['uuid']
+ return defaults
+
+ def _memory_sanity_check(self):
+ if self['memory_static_min'] == 0:
+ self['memory_static_min'] = self['memory_dynamic_min']
+
+ # If the static max is not set, let's set it to dynamic max.
+ # If the static max is smaller than static min, then fix it!
+ self['memory_static_max'] = max(self['memory_static_max'],
+ self['memory_dynamic_max'],
+ self['memory_static_min'])
+
+ for mem_type in ('memory_static_min', 'memory_static_max'):
+ if self[mem_type] <= 0:
+ raise XendConfigError('Memory value too low for %s: %d' %
+ (mem_type, self[mem_type]))
+
+ def _actions_sanity_check(self):
+ for event in ['shutdown', 'reboot', 'crash']:
+ if self['actions_after_' + event] not in CONFIG_RESTART_MODES:
+ raise XendConfigError('Invalid event handling mode: ' +
+ event)
- def _populate_from_sxp(self, parsed):
+ def validate(self):
+ self._memory_sanity_check()
+ self._actions_sanity_check()
+
+ def _dominfo_to_xapi(self, dominfo):
+ self['domid'] = dominfo['domid']
+ self['online_vcpus'] = dominfo['online_vcpus']
+ self['max_vcpu_id'] = dominfo['max_vcpu_id']
+ self['memory_dynamic_min'] = (dominfo['mem_kb'] + 1023)/1024
+ self['memory_dynamic_max'] = (dominfo['maxmem_kb'] + 1023)/1024
+ self['cpu_time'] = dominfo['cpu_time']/1e9
+ # TODO: i don't know what the security stuff expects here
+ if dominfo.get('ssidref'):
+ self['security'] = [['ssidref', dominfo['ssidref']]]
+ self['shutdown_reason'] = dominfo['shutdown_reason']
+
+ # parse state into Xen API states
+ self['running'] = dominfo['running']
+ self['crashed'] = dominfo['crashed']
+ self['dying'] = dominfo['dying']
+ self['shutdown'] = dominfo['shutdown']
+ self['paused'] = dominfo['paused']
+ self['blocked'] = dominfo['blocked']
+
+ if 'name' in dominfo:
+ self['name_label'] = dominfo['name']
+
+ if 'handle' in dominfo:
+ self['uuid'] = uuid.toString(dominfo['handle'])
+
+ def _parse_sxp(self, sxp_cfg):
""" Populate this XendConfig using the parsed SXP.
+ @param sxp_cfg: Parsed SXP Configuration
+ @type sxp_cfg: list of lists
@rtype: dictionary
+ @return: A dictionary containing the parsed options of the SXP.
"""
cfg = {}
# First step is to convert deprecated options to
# current equivalents.
- restart = sxp.child_value(parsed, 'restart')
+ restart = sxp.child_value(sxp_cfg, 'restart')
if restart:
if restart == 'onreboot':
cfg['on_poweroff'] = 'destroy'
'restart = \'%s\'', restart)
# Only extract options we know about.
- all_params = VM_CONFIG_ENTRIES + ROUNDTRIPPING_CONFIG_ENTRIES + \
- STATIC_CONFIG_ENTRIES
-
- for key, typeconv in all_params:
- val = sxp.child_value(parsed, key)
+ extract_keys = LEGACY_UNSUPPORTED_BY_XENAPI_CFG
+ extract_keys += XENAPI_CFG_TO_LEGACY_CFG.values()
+
+ for key in extract_keys:
+ val = sxp.child_value(sxp_cfg, key)
if val:
try:
- cfg[key] = typeconv(val)
+ try:
+ cfg[key] = LEGACY_CFG_TYPES[key](val)
+ except KeyError:
+ cfg[key] = val
except ValueError:
pass
- # Manually extract other complex configuration
- # options.
-
- cfg['backend'] = []
- for c in sxp.children(parsed, 'backend'):
- cfg['backend'].append(sxp.name(sxp.child0(c)))
-
# Parsing the device SXP's. In most cases, the SXP looks
# like this:
#
# Hence we deal with pci device configurations outside of
# the regular device parsing.
- cfg['device'] = {}
- for dev in sxp.children(parsed, 'device'):
+ cfg['devices'] = {}
+ for dev in sxp.children(sxp_cfg, 'device'):
config = sxp.child0(dev)
dev_type = sxp.name(config)
dev_info = {}
if dev_type == 'pci':
- continue
-
- for opt, val in config[1:]:
- dev_info[opt] = val
- log.debug("XendConfig: reading device: %s" % dev_info)
- # create uuid if it doesn't
- dev_uuid = dev_info.get('uuid', uuid.createString())
- dev_info['uuid'] = dev_uuid
- cfg['device'][dev_uuid] = (dev_type, dev_info)
-
- # deal with PCI device configurations if they exist
- for dev in sxp.children(parsed, 'device'):
- config = sxp.child0(dev)
- dev_type = sxp.name(config)
-
- if dev_type != 'pci':
- continue
-
- dev_attr = sxp.child_value(config, 'dev')
- if isinstance(dev_attr, (types.ListType, types.TupleType)):
+ pci_devs_uuid = sxp.child_value(config, 'uuid',
+ uuid.createString())
+ pci_devs = []
for pci_dev in sxp.children(config, 'dev'):
- dev_info = {}
+ pci_dev_info = {}
for opt, val in pci_dev[1:]:
- dev_info[opt] = val
- log.debug("XendConfig: reading device: %s" % dev_info)
- dev_uuid = dev_info.get('uuid', uuid.createString())
- dev_info['uuid'] = dev_uuid
- cfg['device'][dev_uuid] = (dev_type, dev_info)
-
- else: # Xen 2.0 PCI device configuration
+ pci_dev_info[opt] = val
+ pci_devs.append(pci_dev_info)
+
+ cfg['devices'][pci_devs_uuid] = (dev_type,
+ {'devs': pci_devs,
+ 'uuid': pci_devs_uuid})
+
+ log.debug("XendConfig: reading device: %s" % pci_devs)
+ else:
for opt, val in config[1:]:
dev_info[opt] = val
log.debug("XendConfig: reading device: %s" % dev_info)
# create uuid if it doesn't
dev_uuid = dev_info.get('uuid', uuid.createString())
dev_info['uuid'] = dev_uuid
- cfg['device'][dev_uuid] = (dev_type, dev_info)
+ cfg['devices'][dev_uuid] = (dev_type, dev_info)
+
# Extract missing data from configuration entries
- if 'image' in cfg:
- image_vcpus = sxp.child_value(cfg['image'], 'vcpus')
+ image_sxp = sxp.child_value(sxp_cfg, 'image', [])
+ if image_sxp:
+ image_vcpus = sxp.child_value(image_sxp, 'vcpus')
if image_vcpus is not None:
try:
- if 'vcpus' not in cfg:
- cfg['vcpus'] = int(image_vcpus)
- elif cfg['vcpus'] != int(image_vcpus):
- cfg['vcpus'] = int(image_vcpus)
+ if 'vcpus_number' not in cfg:
+ cfg['vcpus_number'] = int(image_vcpus)
+ elif cfg['vcpus_number'] != int(image_vcpus):
+ cfg['vcpus_number'] = int(image_vcpus)
log.warn('Overriding vcpus from %d to %d using image'
- 'vcpus value.', cfg['vcpus'])
+ 'vcpus value.', cfg['vcpus_number'])
except ValueError, e:
raise XendConfigError('integer expeceted: %s: %s' %
- str(cfg['image']), e)
+ image_sxp, e)
# Deprecated cpu configuration
if 'cpu' in cfg:
except ValueError, e:
raise XendConfigError('cpus = %s: %s' % (cfg['cpus'], e))
- # Parse image SXP outside of image.py
- # - used to be only done in image.py
- if 'image' in cfg:
- cfg['kernel_kernel'] = sxp.child_value(cfg['image'], 'kernel','')
- cfg['kernel_initrd'] = sxp.child_value(cfg['image'], 'ramdisk','')
- kernel_args = sxp.child_value(cfg['image'], 'args', '')
-
- # attempt to extract extra arguments from SXP config
- arg_ip = sxp.child_value(cfg['image'], 'ip')
- if arg_ip: kernel_args += ' ip=%s' % arg_ip
- arg_root = sxp.child_value(cfg['image'], 'root')
- if arg_root: kernel_args += ' root=%s' % arg_root
-
- cfg['kernel_args'] = kernel_args
+ if 'security' in cfg and isinstance(cfg['security'], str):
+ cfg['security'] = sxp.from_string(cfg['security'])
# TODO: get states
- old_state = sxp.child_value(parsed, 'state')
+ old_state = sxp.child_value(sxp_cfg, 'state')
if old_state:
for i in range(len(CONFIG_OLD_DOM_STATES)):
cfg[CONFIG_OLD_DOM_STATES[i]] = int(old_state[i] != '-')
- # Xen API extra cfgs
- # ------------------
- cfg['vif_refs'] = []
- cfg['vbd_refs'] = []
- cfg['vtpm_refs'] = []
- for dev_uuid, (dev_type, dev_info) in cfg['device'].items():
- if dev_type == 'vif':
- cfg['vif_refs'].append(dev_uuid)
- elif dev_type in ('vbd','tap'):
- cfg['vbd_refs'].append(dev_uuid)
- elif dev_type == 'vtpm':
- cfg['vtpm_refs'].append(dev_uuid)
-
return cfg
+
+ def _sxp_to_xapi(self, sxp_cfg):
+ """Read in an SXP Configuration object and
+ populate at much of the Xen API with valid values.
+ """
+ cfg = self._parse_sxp(sxp_cfg)
- def _populate_from_xenapi_vm(self, xenapi_vm):
- cfg = {}
-
- for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():
+ # Convert parameters that can be directly mapped from
+ # the Legacy Config to Xen API Config
+
+ for apikey, cfgkey in XENAPI_CFG_TO_LEGACY_CFG.items():
try:
- if apikey in XENAPI_INT_CFG:
- cfg[cfgkey] = int(xenapi_vm[apikey])
- else:
- cfg[cfgkey] = xenapi_vm[apikey]
+ self[apikey] = LEGACY_CFG_TYPES[cfgkey](cfg[cfgkey])
except KeyError:
pass
- # Reconstruct image SXP
- # TODO: get rid of SXP altogether from here
- sxp_image = ['linux']
- if xenapi_vm['kernel_kernel']:
- sxp_image.append(['kernel', xenapi_vm['kernel_kernel']])
- if xenapi_vm['kernel_initrd']:
- sxp_image.append(['ramdisk', xenapi_vm['kernel_initrd']])
- if xenapi_vm['kernel_args']:
- sxp_image.append(['args', xenapi_vm['kernel_args']])
-
- cfg['image'] = prettyprintstring(sxp_image)
-
- # make sure device structures are there.
- if 'device' not in cfg:
- cfg['device'] = {}
- if 'vif_refs' not in cfg:
- cfg['vif_refs'] = []
- if 'vbd_refs' not in cfg:
- cfg['vbd_refs'] = []
- if 'vtpm_refs' not in cfg:
- cfg['vtpm_refs'] = []
+ # Convert Legacy "image" config to Xen API kernel_*
+ # configuration
+ image_sxp = sxp.child_value(sxp_cfg, 'image', [])
+ if image_sxp:
+ self['kernel_kernel'] = sxp.child_value(image_sxp, 'kernel','')
+ self['kernel_initrd'] = sxp.child_value(image_sxp, 'ramdisk','')
+ kernel_args = sxp.child_value(image_sxp, 'args', '')
- return cfg
+ # attempt to extract extra arguments from SXP config
+ arg_ip = sxp.child_value(image_sxp, 'ip')
+ if arg_ip and not re.search(r'ip=[0-9\.]+', kernel_args):
+ kernel_args += ' ip=%s' % arg_ip
+ arg_root = sxp.child_value(image_sxp, 'root')
+ if arg_root and not re.search(r'root=[^ ]+', kernel_args):
+ kernel_args += ' root=%s' % arg_root
+
+ self['kernel_args'] = kernel_args
+
+ # Convert Legacy HVM parameters to Xen API configuration
+ self['platform_std_vga'] = cfg.get('std-vga', 0)
+ self['platform_serial'] = cfg.get('serial', '')
+ self['platform_localtime'] = cfg.get('localtime', 0)
+ self['platform_enable_audio'] = cfg.get('soundhw', 0)
+
+ # Convert path to bootloader to boot_method
+ if not cfg.get('bootloader'):
+ if self.get('kernel_kernel','').endswith('hvmloader'):
+ self['boot_method'] = 'bios'
+ else:
+ self['boot_method'] = 'kernel_external'
+ else:
+ self['boot_method'] = 'grub'
+
+ # make sure a sane maximum is set
+ if self['memory_static_max'] <= 0:
+ self['memory_static_max'] = self['memory_static_min']
+
+ self['memory_dynamic_max'] = self['memory_static_max']
+ self['memory_dynamic_min'] = self['memory_static_min']
+ # set device references in the configuration
+ self['devices'] = cfg.get('devices', {})
+
+ self['vif_refs'] = []
+ self['vbd_refs'] = []
+ self['vtpm_refs'] = []
+ for dev_uuid, (dev_type, dev_info) in self['devices'].items():
+ if dev_type == 'vif':
+ self['vif_refs'].append(dev_uuid)
+ elif dev_type in ('vbd','tap'):
+ self['vbd_refs'].append(dev_uuid)
+ elif dev_type in ('vtpm',):
+ self['vtpm_refs'].append(dev_uuid)
+
- def _sync_xen_api_from_legacy_api(self):
- """ Sync all the attributes that is supported by the Xen API
- from the legacy API configuration.
+ def _sxp_to_xapi_unsupported(self, sxp_cfg):
+ """Read in an SXP configuration object and populate
+ values are that not related directly supported in
+ the Xen API.
"""
- for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():
- if cfgkey in self:
- self.xenapi[apikey] = self[cfgkey]
- def _sync_legacy_api_from_xen_api(self):
- for cfgkey, apikey in LEGACY_CFG_TO_XENAPI_CFG.items():
- if apikey in self.xenapi:
- self[cfgkey] = self.xenapi[apikey]
+ # Parse and convert parameters used to configure
+ # the image (as well as HVM images)
+ image_sxp = sxp.child_value(sxp_cfg, 'image', [])
+ if image_sxp:
+ image = {}
+ image['type'] = sxp.name(image_sxp)
+ for arg, conv in LEGACY_IMAGE_CFG:
+ val = sxp.child_value(image_sxp, arg, None)
+ if val != None:
+ image[arg] = conv(val)
+
+ image_hvm = {}
+ for arg, conv in LEGACY_IMAGE_HVM_CFG:
+ val = sxp.child_value(image_sxp, arg, None)
+ if val != None:
+ image_hvm[arg] = conv(val)
+
+ image_hvm_devices = {}
+ for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
+ val = sxp.child_value(image_sxp, arg, None)
+ if val != None:
+ image_hvm_devices[arg] = conv(val)
+ if image_hvm or image_hvm_devices:
+ image['hvm'] = image_hvm
+ image['hvm']['devices'] = image_hvm_devices
- def _populate_from_xml(self, parsed_xml):
- raise NotImplementedError
+ self['image'] = image
- def _populate_from_python_config(self, parsed_py):
- raise NotImplementedError
+ for apikey, imgkey in XENAPI_HVM_CFG.items():
+ val = sxp.child(image_sxp, imgkey, None)
+ if val != None:
+ self[apikey] = val
+
+ # extract backend value
+
+ backend = []
+ for c in sxp.children(sxp_cfg, 'backend'):
+ backend.append(sxp.name(sxp.child0(c)))
+ if backend:
+ self['backend'] = backend
+
+ if self['image'].has_key('hvm'):
+ self['builder'] = 'hvm'
+
+ # Parse and convert other Non Xen API parameters.
+ def _set_cfg_if_exists(sxp_arg):
+ val = sxp.child_value(sxp_cfg, sxp_arg)
+ if val != None:
+ if LEGACY_CFG_TYPES.get(sxp_arg):
+ self[sxp_arg] = LEGACY_CFG_TYPES[sxp_arg](val)
+ else:
+ self[sxp_arg] = val
+
+ _set_cfg_if_exists('shadow_memory')
+ _set_cfg_if_exists('security')
+ _set_cfg_if_exists('features')
+ _set_cfg_if_exists('on_xend_stop')
+ _set_cfg_if_exists('on_xend_start')
+ _set_cfg_if_exists('vcpu_avail')
+ _set_cfg_if_exists('max_vcpu_id') # TODO, deprecated?
+
+ # Parse and store runtime configuration
+ _set_cfg_if_exists('start_time')
+ _set_cfg_if_exists('online_vcpus')
+ _set_cfg_if_exists('cpu_time')
+ _set_cfg_if_exists('shutdown_reason')
+ _set_cfg_if_exists('up_time')
+ _set_cfg_if_exists('status') # TODO, deprecated
+
+ def _add_xapi_unsupported(self):
+ """Updates the configuration object with entries that are not
+ officially supported by the Xen API but is required for
+ the rest of Xend to function.
+ """
+ pass
def _get_old_state_string(self):
+ """Returns the old xm state string.
+ @rtype: string
+ @return: old state string
+ """
state_string = ''
for state_name in CONFIG_OLD_DOM_STATES:
on_off = self.get(state_name, 0)
return state_string
- def get_sxp(self, domain = None, ignore_devices = False, ignore = []):
+
+ def update_config(self, dominfo):
+ """Update configuration with the output from xc.domain_getinfo().
+
+ @param dominfo: Domain information via xc.domain_getinfo()
+ @type dominfo: dict
+ """
+ self._dominfo_to_xapi(dominfo)
+ self.validate()
+
+ def to_xml(self):
+ """Return an XML string representing the configuration."""
+ pass
+
+ def to_sxp(self, domain = None, ignore_devices = False, ignore = []):
""" Get SXP representation of this config object.
+ Incompat: removed store_mfn, console_mfn
+
@keyword domain: (optional) XendDomainInfo to get extra information
from such as domid and running devices.
@type domain: XendDomainInfo
if domain.getDomid() is not None:
sxpr.append(['domid', domain.getDomid()])
- for cfg, typefunc in ROUNDTRIPPING_CONFIG_ENTRIES:
- if cfg in self:
- if self[cfg] is not None:
- sxpr.append([cfg, self[cfg]])
+ for xenapi, legacy in XENAPI_CFG_TO_LEGACY_CFG.items():
+ if self.has_key(xenapi) and self[xenapi] not in (None, []):
+ sxpr.append([legacy, self[xenapi]])
- if 'image' in self and self['image'] is not None:
- sxpr.append(['image', self['image']])
- if 'security' in self and self['security']:
- sxpr.append(['security', self['security']])
- if 'shutdown_reason' in self:
- sxpr.append(['shutdown_reason', self['shutdown_reason']])
- if 'cpu_time' in self:
- sxpr.append(['cpu_time', self['cpu_time']/1e9])
-
- sxpr.append(['online_vcpus', self['online_vcpus']])
+ for legacy in LEGACY_UNSUPPORTED_BY_XENAPI_CFG:
+ if legacy in ('domid', 'uuid'): # skip these
+ continue
+ if self.has_key(legacy) and self[legacy] not in (None, []):
+ sxpr.append([legacy, self[legacy]])
- if 'start_time' in self:
- uptime = time.time() - self['start_time']
- sxpr.append(['up_time', str(uptime)])
- sxpr.append(['start_time', str(self['start_time'])])
+ if 'image' in self and self['image']:
+ sxpr.append(['image', self.image_sxpr()])
- if domain:
- sxpr.append(['status', str(domain.state)])
- else:
- sxpr.append(['status', str(DOM_STATE_HALTED)])
+ sxpr.append(['status', domain.state])
+ sxpr.append(['memory_dynamic_min', self.get('memory_dynamic_min')])
+ sxpr.append(['memory_dynamic_max', self.get('memory_dynamic_max')])
if domain.getDomid() is not None:
sxpr.append(['state', self._get_old_state_string()])
- sxpr.append(['memory_dynamic_max', self.get('memory_dynamic_max',
- self['memory'])])
-
- # For save/restore migration
if domain:
if domain.store_mfn:
sxpr.append(['store_mfn', domain.store_mfn])
if domain.console_mfn:
sxpr.append(['console_mfn', domain.console_mfn])
+
# Marshall devices (running or from configuration)
if not ignore_devices:
for cls in XendDevices.valid_devices():
except:
log.exception("dumping sxp from device controllers")
pass
-
+
# if we didn't find that device, check the existing config
# for a device in the same class
if not found:
if dev_type == cls:
sxpr.append(['device', dev_info])
- return sxpr
+ return sxpr
+
+ def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None):
+ """Add a device configuration in SXP format or XenAPI struct format.
- def validate(self):
- """ Validate the configuration and fill in missing configuration
- with defaults.
- """
+ For SXP, it could be either:
- # Fill in default values
- for key, default_func in DEFAULT_CONFIGURATION:
- if key not in self or self[key] == None:
- self[key] = default_func(self)
-
- # Basic sanity checks
- if 'image' in self and isinstance(self['image'], str):
- self['image'] = sxp.from_string(self['image'])
- if 'security' in self and isinstance(self['security'], str):
- self['security'] = sxp.from_string(self['security'])
- if self['memory'] == 0 and 'mem_kb' in self:
- self['memory'] = (self['mem_kb'] + 1023)/1024
- if self['memory'] <= 0:
- raise XendConfigError('Invalid memory size: %s' %
- str(self['memory']))
-
- self['maxmem'] = max(self['memory'], self['maxmem'])
-
- # convert mem_kb from domain_getinfo to something more descriptive
- if 'mem_kb' in self:
- self['memory_dynamic_max'] = (self['mem_kb'] + 1023)/1024
-
- # Verify devices
- for d_uuid, (d_type, d_info) in self['device'].items():
- if d_type not in XendDevices.valid_devices() and \
- d_type not in XendDevices.pseudo_devices():
- raise XendConfigError('Invalid device (%s)' % d_type)
-
- # Verify restart modes
- for event in ('on_poweroff', 'on_reboot', 'on_crash'):
- if self[event] not in CONFIG_RESTART_MODES:
- raise XendConfigError('Invalid restart event: %s = %s' % \
- (event, str(self[event])))
-
- # Verify that {vif,vbd}_refs are here too
- if 'vif_refs' not in self:
- self['vif_refs'] = []
- if 'vbd_refs' not in self:
- self['vbd_refs'] = []
- if 'vtpm_refs' not in self:
- self['vtpm_refs'] = []
+ [device, [vbd, [uname ...]]
- def device_add(self, dev_type, cfg_sxp = None, cfg_xenapi = None):
+ or:
+
+ [vbd, [uname ..]]
+
+ @type cfg_sxp: list of lists (parsed sxp object)
+ @param cfg_sxp: SXP configuration object
+ @type cfg_xenapi: dict
+ @param cfg_xenapi: A device configuration from Xen API (eg. vbd,vif)
+ @rtype: string
+ @return: Assigned UUID of the device.
+ """
if dev_type not in XendDevices.valid_devices() and \
- dev_type not in XendDevices.pseudo_devices():
+ dev_type not in XendDevices.pseudo_devices():
raise XendConfigError("XendConfig: %s not a valid device type" %
dev_type)
log.debug("XendConfig.device_add: %s" % str(cfg_xenapi))
if cfg_sxp:
+ if sxp.child0(cfg_sxp) == 'device':
+ config = sxp.child0(cfg_sxp)
+ else:
+ config = cfg_sxp
+
+ dev_type = sxp.name(config)
dev_info = {}
try:
- for opt, val in cfg_sxp[1:]:
+ for opt, val in config[1:]:
dev_info[opt] = val
except ValueError:
pass # SXP has no options for this device
+
+ def _get_config_ipaddr(config):
+ val = []
+ for ipaddr in sxp.children(config, elt='ip'):
+ val.append(sxp.child0(ipaddr))
+ return val
+
+ if dev_type == 'vif' and 'ip' in dev_info:
+ dev_info['ip'] = _get_config_ipaddr(config)
+
+ if dev_type == 'vbd':
+ if dev_info.get('dev', '').startswith('ioemu:'):
+ dev_info['driver'] = 'ioemu'
+ else:
+ dev_info['driver'] = 'paravirtualised'
+
+
# create uuid if it doesn't exist
dev_uuid = dev_info.get('uuid', uuid.createString())
dev_info['uuid'] = dev_uuid
- self['device'][dev_uuid] = (dev_type, dev_info)
- if dev_type in ('vif', 'vbd'):
+
+ # store dev references by uuid for certain device types
+ self['devices'][dev_uuid] = (dev_type, dev_info)
+ if dev_type in ('vif', 'vbd', 'vtpm'):
self['%s_refs' % dev_type].append(dev_uuid)
elif dev_type in ('tap',):
self['vbd_refs'].append(dev_uuid)
+
return dev_uuid
if cfg_xenapi:
dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
dev_info['uuid'] = dev_uuid
- self['device'][dev_uuid] = (dev_type, dev_info)
+ self['devices'][dev_uuid] = (dev_type, dev_info)
self['vif_refs'].append(dev_uuid)
return dev_uuid
- elif dev_type == 'vbd':
- dev_info['uname'] = cfg_xenapi.get('image', None)
- dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
+ elif dev_type in ('vbd', 'tap'):
+ if dev_type == 'vbd':
+ dev_info['uname'] = cfg_xenapi.get('image', None)
+ dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
+ elif dev_type == 'tap':
+ dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
+ dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
+
+ dev_info['driver'] = cfg_xenapi.get('driver')
+
if cfg_xenapi.get('mode') == 'RW':
dev_info['mode'] = 'w'
else:
dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
dev_info['uuid'] = dev_uuid
- self['device'][dev_uuid] = (dev_type, dev_info)
+ self['devices'][dev_uuid] = (dev_type, dev_info)
self['vbd_refs'].append(dev_uuid)
return dev_uuid
+
+ return ''
- elif dev_type == 'vtpm':
- if cfg_xenapi.get('type'):
- dev_info['type'] = cfg_xenapi.get('type')
- dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
- dev_info['uuid'] = dev_uuid
- self['device'][dev_uuid] = (dev_type, dev_info)
- self['vtpm_refs'].append(dev_uuid)
- return dev_uuid
+ def device_update(self, dev_uuid, cfg_sxp):
+ """Update an existing device with the new configuration.
- elif dev_type == 'tap':
- dev_info['uname'] = 'tap:qcow:%s' % cfg_xenapi.get('image')
- dev_info['dev'] = '%s:disk' % cfg_xenapi.get('device')
-
- if cfg_xenapi.get('mode') == 'RW':
- dev_info['mode'] = 'w'
- else:
- dev_info['mode'] = 'r'
+ @rtype: boolean
+ @return: Returns True if succesfully found and updated a device conf
+ """
+ if dev_uuid in self['devices']:
+ config = sxp.child0(cfg_sxp)
+ dev_type = sxp.name(config)
+ dev_info = {}
+
+ try:
+ for opt, val in config[1:]:
+ self['devices'][opt] = val
+ except ValueError:
+ pass # SXP has no options for this device
+
+ return True
+
+ return False
- dev_uuid = cfg_xenapi.get('uuid', uuid.createString())
- dev_info['uuid'] = dev_uuid
- self['device'][dev_uuid] = (dev_type, dev_info)
- self['vbd_refs'].append(dev_uuid)
- return dev_uuid
-
- return ''
def device_sxpr(self, dev_uuid = None, dev_type = None, dev_info = None):
"""Get Device SXPR by either giving the device UUID or (type, config).
@return: device config sxpr
"""
sxpr = []
- if dev_uuid != None and dev_uuid in self['device']:
- dev_type, dev_info = self['device'][dev_uuid]
+ if dev_uuid != None and dev_uuid in self['devices']:
+ dev_type, dev_info = self['devices'][dev_uuid]
if dev_type == None or dev_info == None:
raise XendConfigError("Required either UUID or device type and "
"""Returns the SXPR for all devices in the current configuration."""
sxprs = []
pci_devs = []
- for dev_type, dev_info in self['device'].values():
+
+ if 'devices' in self:
+ return sxprs
+
+ for dev_type, dev_info in self['devices'].values():
if dev_type == 'pci': # special case for pci devices
- pci_devs.append(dev_info)
+ sxpr = [['uuid', dev_info['uuid']]]
+ for pci_dev_info in dev_info['devs']:
+ pci_dev_sxpr = ['dev']
+ for opt, val in pci_dev_info.items():
+ pci_dev_sxpr.append([opt, val])
+ sxpr.append(pci_dev_sxpr)
+ sxprs.append((dev_type, sxpr))
else:
sxpr = self.device_sxpr(dev_type = dev_type,
dev_info = dev_info)
sxprs.append((dev_type, sxpr))
- # if we have any pci_devs, we parse them differently into
- # one single pci SXP entry.
- if pci_devs:
- sxpr = ['pci',]
- for dev_info in pci_devs:
- dev_sxpr = self.device_sxpr(dev_type = 'dev',
- dev_info = dev_info)
- sxpr.append(dev_sxpr)
- sxprs.append(('pci', sxpr))
-
return sxprs
-
+ def image_sxpr(self):
+ """Returns a backwards compatible image SXP expression that is
+ used in xenstore's /vm/<uuid>/image value and xm list."""
+ image = [self['image'].get('type', 'linux')]
+ if self.has_key('kernel_kernel'):
+ image.append(['kernel', self['kernel_kernel']])
+ if self.has_key('kernel_initrd') and self['kernel_initrd']:
+ image.append(['ramdisk', self['kernel_initrd']])
+ if self.has_key('kernel_args') and self['kernel_args']:
+ image.append(['args', self['kernel_args']])
+
+ for arg, conv in LEGACY_IMAGE_CFG:
+ if self['image'].has_key(arg):
+ image.append([arg, self['image'][arg]])
+
+ if 'hvm' in self['image']:
+ for arg, conv in LEGACY_IMAGE_HVM_CFG:
+ if self['image']['hvm'].has_key(arg):
+ image.append([arg, self['image']['hvm'][arg]])
+
+ if 'hvm' in self['image'] and 'devices' in self['image']['hvm']:
+ for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
+ if self['image']['hvm']['devices'].has_key(arg):
+ image.append([arg,
+ self['image']['hvm']['devices'][arg]])
+
+ return image
+
+ def update_with_image_sxp(self, image_sxp):
+ # Convert Legacy "image" config to Xen API kernel_*
+ # configuration
+ self['kernel_kernel'] = sxp.child_value(image_sxp, 'kernel','')
+ self['kernel_initrd'] = sxp.child_value(image_sxp, 'ramdisk','')
+ kernel_args = sxp.child_value(image_sxp, 'args', '')
+
+ # attempt to extract extra arguments from SXP config
+ arg_ip = sxp.child_value(image_sxp, 'ip')
+ if arg_ip and not re.search(r'ip=[0-9\.]', kernel_args):
+ kernel_args += ' ip=%s' % arg_ip
+ arg_root = sxp.child_value(image_sxp, 'root')
+ if arg_root and not re.search(r'root=', kernel_args):
+ kernel_args += ' root=%s' % arg_root
+ self['kernel_args'] = kernel_args
+
+ # Store image SXP in python dictionary format
+ image = {}
+ image['type'] = sxp.name(image_sxp)
+ for arg, conv in LEGACY_IMAGE_CFG:
+ val = sxp.child_value(image_sxp, arg, None)
+ if val != None:
+ image[arg] = conv(val)
+
+ image_hvm = {}
+ for arg, conv in LEGACY_IMAGE_HVM_CFG:
+ val = sxp.child_value(image_sxp, arg, None)
+ if val != None:
+ image_hvm[arg] = conv(val)
+
+ image_hvm_devices = {}
+ for arg, conv in LEGACY_IMAGE_HVM_DEVICES_CFG:
+ val = sxp.child_value(image_sxp, arg, None)
+ if val != None:
+ image_hvm_devices[arg] = conv(val)
+
+ if image_hvm or image_hvm_devices:
+ image['hvm'] = image_hvm
+ image['hvm']['devices'] = image_hvm_devices
+
+ self['image'] = image
+
+ for apikey, imgkey in XENAPI_HVM_CFG.items():
+ val = sxp.child(image_sxp, imgkey, None)
+ if val != None:
+ self[apikey] = val
+
+
#
# debugging
#
"""
log.debug("Adding Domain: %s" % info.getDomid())
self.domains[info.getDomid()] = info
+
+ # update the managed domains with a new XendDomainInfo object
+ # if we are keeping track of it.
+ if info.get_uuid() in self.managed_domains:
+ self._managed_domain_register(info)
def _remove_domain(self, info, domid = None):
"""Remove the domain from the list of running domains
self.domains_lock.acquire()
try:
try:
- xeninfo = XendConfig(xenapi_vm = xenapi_vm)
+ xeninfo = XendConfig(xapi = xenapi_vm)
dominfo = XendDomainInfo.createDormant(xeninfo)
log.debug("Creating new managed domain: %s: %s" %
(dominfo.getName(), dominfo.get_uuid()))
self.domains_lock.acquire()
try:
try:
- xeninfo = XendConfig(sxp = config)
- dominfo = XendDomainInfo.createDormant(xeninfo)
+ domconfig = XendConfig(sxp_obj = config)
+ dominfo = XendDomainInfo.createDormant(domconfig)
log.debug("Creating new managed domain: %s" %
dominfo.getName())
self._managed_domain_register(dominfo)
from xen.util import security
from xen.xend import balloon, sxp, uuid, image, arch
-from xen.xend import XendRoot, XendNode
+from xen.xend import XendRoot, XendNode, XendConfig
from xen.xend.XendBootloader import bootloader
-from xen.xend.XendConfig import XendConfig
from xen.xend.XendError import XendError, VmError
from xen.xend.XendDevices import XendDevices
from xen.xend.xenstore.xstransact import xstransact, complete
"""
log.debug("XendDomainInfo.create(%s)", config)
- vm = XendDomainInfo(XendConfig(sxp = config))
+ vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config))
try:
vm.start()
except:
assert not info['dying']
- xeninfo = XendConfig(cfg = info)
+ xeninfo = XendConfig.XendConfig(dominfo = info)
domid = xeninfo['domid']
- uuid1 = xeninfo['handle']
- xeninfo['uuid'] = uuid.toString(uuid1)
+ uuid1 = uuid.fromString(xeninfo['uuid'])
needs_reinitialising = False
dompath = GetDomainPath(domid)
def restore(config):
"""Create a domain and a VM object to do a restore.
- @param config: Domain configuration object
+ @param config: Domain SXP configuration
@type config: list of lists. (see C{create})
@rtype: XendDomainInfo
"""
log.debug("XendDomainInfo.restore(%s)", config)
- vm = XendDomainInfo(XendConfig(sxp = config), resume = True)
+ vm = XendDomainInfo(XendConfig.XendConfig(sxp_obj = config),
+ resume = True)
try:
vm.resume()
return vm
vm.destroy()
raise
-def createDormant(xeninfo):
+def createDormant(domconfig):
"""Create a dormant/inactive XenDomainInfo without creating VM.
This is for creating instances of persistent domains that are not
yet start.
- @param xeninfo: Parsed configuration
- @type xeninfo: dictionary
+ @param domconfig: Parsed configuration
+ @type domconfig: XendConfig object
@rtype: XendDomainInfo
@return: A up and running XendDomainInfo instance
@raise XendError: Errors with configuration.
"""
- log.debug("XendDomainInfo.createDormant(%s)", xeninfo)
+ log.debug("XendDomainInfo.createDormant(%s)", domconfig)
# domid does not make sense for non-running domains.
- xeninfo.pop('domid', None)
- vm = XendDomainInfo(XendConfig(cfg = xeninfo))
+ domconfig.pop('domid', None)
+ vm = XendDomainInfo(domconfig)
return vm
def domain_by_name(name):
#if not self._infoIsSet('uuid'):
# self.info['uuid'] = uuid.toString(uuid.create())
- #REMOVE: domid logic can be shortened
- #if domid is not None:
- # self.domid = domid
- #elif info.has_key('dom'):
- # self.domid = int(info['dom'])
- #else:
- # self.domid = None
-
self.vmpath = XS_VMROOT + self.info['uuid']
self.dompath = dompath
self.vmWatch = None
self.shutdownWatch = None
self.shutdownStartTime = None
+ self._resume = resume
self.state = DOM_STATE_HALTED
self.state_updated = threading.Condition()
if augment:
self._augmentInfo(priv)
- self._checkName(self.info['name'])
- self.setResume(resume)
+ self._checkName(self.info['name_label'])
#
if self.domid == 0:
raise XendError('Domain 0 cannot be shutdown')
- if not reason in DOMAIN_SHUTDOWN_REASONS.values():
+ if reason not in DOMAIN_SHUTDOWN_REASONS.values():
raise XendError('Invalid reason: %s' % reason)
self._storeDom("control/shutdown", reason)
"""Create a new device.
@param dev_config: device configuration
- @type dev_config: dictionary (parsed config)
+ @type dev_config: SXP object (parsed config)
"""
log.debug("XendDomainInfo.device_create: %s" % dev_config)
dev_type = sxp.name(dev_config)
- devid = self._createDevice(dev_type, dev_config)
- self.info.device_add(dev_type, cfg_sxp = dev_config)
+ dev_uuid = self.info.device_add(dev_type, cfg_sxp = dev_config)
+ dev_config_dict = self.info['devices'][dev_uuid][1]
+ log.debug("XendDomainInfo.device_create: %s" % dev_config_dict)
+ devid = self._createDevice(dev_type, dev_config_dict)
self._waitForDevice(dev_type, devid)
return self.getDeviceController(dev_type).sxpr(devid)
"""Configure an existing device.
@param dev_config: device configuration
- @type dev_config: dictionary (parsed config)
+ @type dev_config: SXP object (parsed config)
@param devid: device id
@type devid: int
+ @return: Returns True if successfully updated device
+ @rtype: boolean
"""
deviceClass = sxp.name(dev_config)
- self._reconfigureDevice(deviceClass, devid, dev_config)
+
+ # look up uuid of the device
+ dev_control = self.getDeviceController(deviceClass)
+ dev_sxpr = dev_control.sxpr(devid)
+ dev_uuid = sxp.child_value(sxpr, 'uuid')
+ if not dev_uuid:
+ return False
+
+ self.info.device_update(dev_uuid, dev_config)
+ dev_config_dict = self.info['devices'].get(dev_uuid)
+ if dev_config_dict:
+ dev_control.reconfigureDevice(devid, dev_config_dict[1])
+ return True
def waitForDevices(self):
"""Wait for this domain's configured devices to connect.
@param target: In MiB.
"""
log.debug("Setting memory target of domain %s (%d) to %d MiB.",
- self.info['name'], self.domid, target)
+ self.info['name_label'], self.domid, target)
if target <= 0:
raise XendError('Invalid memory size')
- self.info['memory'] = target
+ self.info['memory_static_min'] = target
self.storeVm("memory", target)
self._storeDom("memory/target", target << 10)
# We include the domain name and ID, to help xm.
sxpr = ['domain',
['domid', self.domid],
- ['name', self.info['name']],
- ['vcpu_count', self.info['online_vcpus']]]
+ ['name', self.info['name_label']],
+ ['vcpu_count', self.info['vcpus_number']]]
for i in range(0, self.info['max_vcpu_id']+1):
info = xc.vcpu_getinfo(self.domid, i)
values taken from the store. This recovers those values known
to xend but not to the hypervisor.
"""
- def useIfNeeded(name, val):
- if not self._infoIsSet(name) and val is not None:
- self.info[name] = val
-
+ augment_entries = XendConfig.LEGACY_XENSTORE_VM_PARAMS[:]
if priv:
- entries = VM_STORE_ENTRIES[:]
- entries.remove(('memory', int))
- entries.remove(('maxmem', int))
- else:
- entries = VM_STORE_ENTRIES
- entries.append(('image', str))
- entries.append(('security', str))
+ augment_entries.remove('memory')
+ augment_entries.remove('maxmem')
- map(lambda x, y: useIfNeeded(x[0], y), entries,
- self._readVMDetails(entries))
+ vm_config = self._readVMDetails([(k, XendConfig.LEGACY_CFG_TYPES[k])
+ for k in augment_entries])
+
+ # make returned lists into a dictionary
+ vm_config = dict(zip(augment_entries, vm_config))
+
+ for arg in augment_entries:
+ xapicfg = arg
+ val = vm_config[arg]
+ if val != None:
+ if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG:
+ xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg]
+ self.info[xapiarg] = val
+ else:
+ self.info[arg] = val
- devices = []
+ # read image value
+ image_sxp = self._readVm('image')
+ if image_sxp:
+ self.info.update_with_image_sxp(sxp.from_string(image_sxp))
+ # read devices
+ devices = []
for devclass in XendDevices.valid_devices():
devconfig = self.getDeviceController(devclass).configurations()
if devconfig:
devices.extend(map(lambda conf: (devclass, conf), devconfig))
- if not self.info['device'] and devices is not None:
+ if not self.info['devices'] and devices is not None:
for device in devices:
self.info.device_add(device[0], cfg_sxp = device)
def _recreateDomFunc(self, t):
t.remove()
t.mkdir()
- t.set_permissions({ 'dom' : self.domid })
+ t.set_permissions({'dom' : self.domid})
t.write('vm', self.vmpath)
def _storeDomDetails(self):
to_store = {
'domid': str(self.domid),
'vm': self.vmpath,
- 'name': self.info['name'],
+ 'name': self.info['name_label'],
'console/limit': str(xroot.get_console_limit() * 1024),
- 'memory/target': str(self.info['memory'] * 1024)
+ 'memory/target': str(self.info['memory_static_min'] * 1024)
}
def f(n, v):
return 'offline'
result = {}
- for v in range(0, self.info['vcpus']):
+ for v in range(0, self.info['vcpus_number']):
result["cpu/%d/availability" % v] = availability(v)
return result
log.trace("XendDomainInfo.storeChanged");
changed = False
+
+ # Check whether values in the configuration have
+ # changed in Xenstore.
- def f(x, y):
- if y is not None and self.info[x[0]] != y:
- self.info[x[0]] = y
- changed = True
-
- map(f, VM_CONFIG_PARAMS, self._readVMDetails(VM_CONFIG_PARAMS))
-
- im = self._readVm('image')
- current_im = self.info['image']
- if (im is not None and
- (current_im is None or sxp.to_string(current_im) != im)):
- self.info['image'] = sxp.from_string(im)
+ cfg_vm = ['name', 'on_poweroff', 'on_reboot', 'on_crash']
+
+ vm_details = self._readVMDetails([(k,XendConfig.LEGACY_CFG_TYPES[k])
+ for k in cfg_vm])
+
+ # convert two lists into a python dictionary
+ vm_details = dict(zip(cfg_vm, vm_details))
+
+ for arg, val in vm_details.items():
+ if arg in XendConfig.LEGACY_CFG_TO_XENAPI_CFG:
+ xapiarg = XendConfig.LEGACY_CFG_TO_XENAPI_CFG[arg]
+ if val != None and val != self.info[xapiarg]:
+ self.info[xapiarg] = val
+ changed= True
+
+ # Check whether image definition has been updated
+ image_sxp = self._readVm('image')
+ if image_sxp and image_sxp != self.info.image_sxpr():
+ self.info.update_with_image_sxp(sxp.from_string(image_sxp))
changed = True
if changed:
def setName(self, name):
self._checkName(name)
- self.info['name'] = name
+ self.info['name_label'] = name
self.storeVm("name", name)
def getName(self):
- return self.info['name']
+ return self.info['name_label']
def getDomainPath(self):
return self.dompath
return self.info['features']
def getVCpuCount(self):
- return self.info['vcpus']
+ return self.info['vcpus_number']
def setVCpuCount(self, vcpus):
self.info['vcpu_avail'] = (1 << vcpus) - 1
def getMemoryTarget(self):
"""Get this domain's target memory size, in KB."""
- return self.info['memory'] * 1024
+ return self.info['memory_static_min'] * 1024
def getResume(self):
- return "%s" % self.info['resume']
+ return str(self._resume)
def getCap(self):
- return self.info['cpu_cap']
+ return self.info.get('cpu_cap', 0)
def getWeight(self):
return self.info['cpu_weight']
def setResume(self, state):
- self.info['resume'] = state
+ self._resume = state
def getRestartCount(self):
return self._readVm('xend/restart_count')
return
log.warn('Domain has crashed: name=%s id=%d.',
- self.info['name'], self.domid)
+ self.info['name_label'], self.domid)
if xroot.get_enable_dump():
self.dumpCore()
reason = shutdown_reason(xeninfo['shutdown_reason'])
log.info('Domain has shutdown: name=%s id=%d reason=%s.',
- self.info['name'], self.domid, reason)
+ self.info['name_label'], self.domid, reason)
self._clearRestart()
if timeout < 0:
log.info(
"Domain shutdown timeout expired: name=%s id=%s",
- self.info['name'], self.domid)
+ self.info['name_label'], self.domid)
self.destroy()
finally:
self.refresh_shutdown_lock.release()
def _maybeRestart(self, reason):
# Dispatch to the correct method based upon the configured on_{reason}
# behaviour.
- {"destroy" : self.destroy,
- "restart" : self._restart,
- "preserve" : self._preserve,
- "rename-restart" : self._renameRestart}[self.info['on_' + reason]]()
-
+ actions = {"destroy" : self.destroy,
+ "restart" : self._restart,
+ "preserve" : self._preserve,
+ "rename-restart" : self._renameRestart}
+
+ action_conf = {
+ 'poweroff': 'actions_after_shutdown',
+ 'reboot': 'actions_after_reboot',
+ 'crash': 'actions_after_crash',
+ }
+
+ action_target = self.info.get(action_conf.get(reason))
+ func = actions.get(action_target, None)
+ if func and callable(func):
+ func()
+ else:
+ self.destroy() # default to destroy
def _renameRestart(self):
self._restart(True)
log.error(
'VM %s restarting too fast (%f seconds since the last '
'restart). Refusing to restart to avoid loops.',
- self.info['name'], timeout)
+ self.info['name_label'], timeout)
self.destroy()
return
new_uuid = uuid.createString()
new_name = 'Domain-%s' % new_uuid
log.info("Renaming dead domain %s (%d, %s) to %s (%s).",
- self.info['name'], self.domid, self.info['uuid'],
+ self.info['name_label'], self.domid, self.info['uuid'],
new_name, new_uuid)
self._unwatchVm()
self._releaseDevices()
- self.info['name'] = new_name
+ self.info['name_label'] = new_name
self.info['uuid'] = new_uuid
self.vmpath = XS_VMROOT + new_uuid
self._storeVmDetails()
def _preserve(self):
- log.info("Preserving dead domain %s (%d).", self.info['name'],
+ log.info("Preserving dead domain %s (%d).", self.info['name_label'],
self.domid)
self._unwatchVm()
self._storeDom('xend/shutdown_completed', 'True')
if not corefile:
this_time = time.strftime("%Y-%m%d-%H%M.%S", time.localtime())
corefile = "/var/xen/dump/%s-%s.%s.core" % (this_time,
- self.info['name'], self.domid)
+ self.info['name_label'], self.domid)
if os.path.isdir(corefile):
raise XendError("Cannot dump core in a directory: %s" %
corefile_incomp = corefile+'-incomplete'
os.rename(corefile, corefile_incomp)
log.exception("XendDomainInfo.dumpCore failed: id = %s name = %s",
- self.domid, self.info['name'])
+ self.domid, self.info['name_label'])
raise XendError("Failed to dump core: %s" % str(ex))
#
@raise: VmError for invalid devices
"""
- for (devclass, config) in self.info.all_devices_sxpr():
- if devclass in XendDevices.valid_devices():
+ for (devclass, config) in self.info.get('devices', {}).values():
+ if devclass in XendDevices.valid_devices():
log.info("createDevice: %s : %s" % (devclass, config))
self._createDevice(devclass, config)
# there's nothing more we can do.
log.exception(
"Device release failed: %s; %s; %s",
- self.info['name'], devclass, dev)
+ self.info['name_label'], devclass, dev)
if t.commit():
break
log.debug('XendDomainInfo.constructDomain')
- hvm = (self._infoIsSet('image') and
- sxp.name(self.info['image']) == "hvm")
+ image_cfg = self.info.get('image', {})
+ hvm = image_cfg.has_key('hvm')
+
if hvm:
info = xc.xeninfo()
- if not 'hvm' in info['xen_caps']:
+ if 'hvm' not in info['xen_caps']:
raise VmError("HVM guest support is unavailable: is VT/AMD-V "
"supported by your CPU and enabled in your "
"BIOS?")
if self.domid < 0:
raise VmError('Creating domain failed: name=%s' %
- self.info['name'])
+ self.info['name_label'])
self.dompath = GetDomainPath(self.domid)
self._recreateDom()
# Set maximum number of vcpus in domain
- xc.domain_max_vcpus(self.domid, int(self.info['vcpus']))
+ xc.domain_max_vcpus(self.domid, int(self.info['vcpus_number']))
def _introduceDomain(self):
# if we have a boot loader but no image, then we need to set things
# up by running the boot loader non-interactively
- if self._infoIsSet('bootloader') and not self._infoIsSet('image'):
+ if self.info.get('bootloader') and self.info.get('image'):
self._configureBootloader()
if not self._infoIsSet('image'):
try:
self.image = image.create(self,
+ self.info,
self.info['image'],
- self.info.all_devices_sxpr())
+ self.info['devices'])
localtime = self.info.get('localtime', 0)
if localtime is not None and localtime == 1:
# the various headrooms necessary, given the raw configured
# values. maxmem, memory, and shadow are all in KiB.
maxmem = self.image.getRequiredAvailableMemory(
- self.info['maxmem'] * 1024)
+ self.info['memory_static_min'] * 1024)
memory = self.image.getRequiredAvailableMemory(
- self.info['memory'] * 1024)
+ self.info['memory_static_max'] * 1024)
shadow = self.image.getRequiredShadowMemory(
self.info['shadow_memory'] * 1024,
- self.info['maxmem'] * 1024)
+ self.info['memory_static_max'] * 1024)
# Round shadow up to a multiple of a MiB, as shadow_mem_control
# takes MiB and we must not round down and end up under-providing.
self._createDevices()
- if self.info['bootloader'] not in [None, 'kernel_external']:
+ if self.info['bootloader']:
self.image.cleanupBootloading()
self.info['start_time'] = time.time()
self._stateSet(DOM_STATE_RUNNING)
except RuntimeError, exn:
log.exception("XendDomainInfo.initDomain: exception occurred")
- if self.info['bootloader'] not in [None, 'kernel_external'] \
+ if self.info['bootloader'] not in (None, 'kernel_external') \
and self.image is not None:
self.image.cleanupBootloading()
raise VmError(str(exn))
self.refresh_shutdown_lock.acquire()
try:
self.unwatchShutdown()
-
self._releaseDevices()
if self.image:
def _configureBootloader(self):
"""Run the bootloader if we're configured to do so."""
- if not self.info['bootloader']:
+ if not self.info.get('bootloader'):
return
blcfg = None
# FIXME: this assumes that we want to use the first disk device
- for (n, c) in self.info.all_devices_sxpr():
- if not n or not c or not(n in ["vbd", "tap"]):
+ for devuuid, (devtype, devinfo) in self.info.all_devices_sxpr():
+ if not devtype or not devinfo or devtype not in ('vbd', 'tap'):
continue
- disk = sxp.child_value(c, "uname")
+ disk = devinfo.get('uname')
if disk is None:
continue
fn = blkdev_uname_to_file(disk)
msg = "Had a bootloader specified, but can't find disk"
log.error(msg)
raise VmError(msg)
- self.info['image'] = blcfg
+
+ self.info.update_with_image_sxp(blcfg)
#
# VM Functions
if arch.type == "x86":
# 1MB per vcpu plus 4Kib/Mib of RAM. This is higher than
# the minimum that Xen would allocate if no value were given.
- overhead_kb = self.info['vcpus'] * 1024 + self.info['maxmem'] * 4
+ overhead_kb = self.info['vcpus_number'] * 1024 + \
+ self.info['memory_static_max'] * 4
overhead_kb = ((overhead_kb + 1023) / 1024) * 1024
# The domain might already have some shadow memory
overhead_kb -= xc.shadow_mem_control(self.domid) * 1024
def _storeVmDetails(self):
to_store = {}
- for k in VM_STORE_ENTRIES:
- if self._infoIsSet(k[0]):
- to_store[k[0]] = str(self.info[k[0]])
+ for key in XendConfig.LEGACY_XENSTORE_VM_PARAMS:
+ info_key = XendConfig.LEGACY_CFG_TO_XENAPI_CFG.get(key, key)
+ if self._infoIsSet(info_key):
+ to_store[key] = str(self.info[info_key])
- if self._infoIsSet('image'):
- to_store['image'] = sxp.to_string(self.info['image'])
+ if self.info.get('image'):
+ image_sxpr = self.info.image_sxpr()
+ if image_sxpr:
+ to_store['image'] = sxp.to_string(image_sxpr)
if self._infoIsSet('security'):
secinfo = self.info['security']
#create new security element
self.info.update({'security':
[['ssidref', str(info['ssidref'])]]})
+
#ssidref field not used any longer
if 'ssidref' in info:
info.pop('ssidref')
# make sure state is reset for info
# TODO: we should eventually get rid of old_dom_states
- self.info.update(info)
- self.info.validate()
+ self.info.update_config(info)
if refresh:
self.refreshShutdown(info)
str(self.domid), self.info)
def sxpr(self, ignore_store = False):
- result = self.info.get_sxp(domain = self,
+ result = self.info.to_sxp(domain = self,
ignore_devices = ignore_store)
if not ignore_store and self.dompath:
return dom_uuid
def get_memory_static_max(self):
- return self.info['maxmem']
+ return self.info['memory_static_max']
def get_memory_static_min(self):
- return self.info['memory']
+ return self.info['memory_static_min']
+ def get_memory_dynamic_max(self):
+ return self.info['memory_dynamic_min']
+ def get_memory_dynamic_min(self):
+ return self.info['memory_static_min']
+
+
def get_vcpus_policy(self):
sched_id = xc.sched_id_get()
if sched_id == xen.lowlevel.xc.XEN_SCHEDULER_SEDF:
def get_platform_keymap(self):
return ''
def get_platform_serial(self):
- return '' # TODO
+ return self.info['platform_serial']
def get_platform_localtime(self):
- return False # TODO
+ return self.info['platform_localtime']
def get_platform_clock_offset(self):
- return False # TODO
+ return self.info['platform_clock_offset']
def get_platform_enable_audio(self):
- return False # TODO
+ return self.info['platform_enable_audio']
def get_builder(self):
- return 'Linux' # TODO
+ return self.info['builder']
def get_boot_method(self):
- bootloader = self.info['bootloader']
- if not bootloader or bootloader not in XEN_API_BOOT_TYPE:
- return 'kernel_external'
- return bootloader
-
+ return self.info['boot_method']
def get_kernel_image(self):
return self.info['kernel_kernel']
def get_kernel_initrd(self):
return {} # TODO
def get_on_shutdown(self):
- after_shutdown = self.info.get('on_poweroff')
+ after_shutdown = self.info.get('action_after_shutdown')
if not after_shutdown or after_shutdown not in XEN_API_ON_NORMAL_EXIT:
return XEN_API_ON_NORMAL_EXIT[-1]
return after_shutdown
def get_on_reboot(self):
- after_reboot = self.info.get('on_reboot')
+ after_reboot = self.info.get('action_after_reboot')
if not after_reboot or after_reboot not in XEN_API_ON_NORMAL_EXIT:
return XEN_API_ON_NORMAL_EXIT[-1]
return after_reboot
def get_on_suspend(self):
- after_suspend = self.info.get('on_suspend') # TODO: not supported
+ # TODO: not supported
+ after_suspend = self.info.get('action_after_suspend')
if not after_suspend or after_suspend not in XEN_API_ON_NORMAL_EXIT:
return XEN_API_ON_NORMAL_EXIT[-1]
return after_suspend
def get_on_crash(self):
- after_crash = self.info.get('on_crash')
+ after_crash = self.info.get('action_after_crash')
if not after_crash or after_crash not in XEN_API_ON_CRASH_BEHAVIOUR:
return XEN_API_ON_CRASH_BEHAVIOUR[0]
return after_crash
@rtype: dictionary
"""
- dev_type_config = self.info['device'].get(dev_uuid)
+ dev_type_config = self.info['devices'].get(dev_uuid)
# shortcut if the domain isn't started because
# the devcontrollers will have no better information
config['IO_bandwidth_incoming_kbs'] = 0.0
config['IO_bandwidth_outgoing_kbs'] = 0.0
- if dev_class =='vbd':
+ if dev_class == 'vbd':
config['VDI'] = '' # TODO
config['device'] = config.get('dev', '')
config['driver'] = 'paravirtualised' # TODO
def __str__(self):
return '<domain id=%s name=%s memory=%s state=%s>' % \
- (str(self.domid), self.info['name'],
- str(self.info['memory']), DOM_STATES[self.state])
+ (str(self.domid), self.info['name_label'],
+ str(self.info['memory_static_min']), DOM_STATES[self.state])
__repr__ = __str__
import signal
import xen.lowlevel.xc
-from xen.xend import sxp
from xen.xend.XendError import VmError, XendError
from xen.xend.XendLogging import log
from xen.xend.server.netif import randomMAC
from xen.xend import arch
from xen.xend import FlatDeviceTree
-
xc = xen.lowlevel.xc.xc()
-
MAX_GUEST_CMDLINE = 1024
-def create(vm, imageConfig, deviceConfig):
+def create(vm, vmConfig, imageConfig, deviceConfig):
"""Create an image handler for a vm.
@return ImageHandler instance
"""
- return findImageHandlerClass(imageConfig)(vm, imageConfig, deviceConfig)
+ return findImageHandlerClass(imageConfig)(vm, vmConfig, imageConfig,
+ deviceConfig)
class ImageHandler:
ostype = None
- def __init__(self, vm, imageConfig, deviceConfig):
+ def __init__(self, vm, vmConfig, imageConfig, deviceConfig):
self.vm = vm
self.kernel = None
self.ramdisk = None
self.cmdline = None
- self.configure(imageConfig, deviceConfig)
+ self.configure(vmConfig, imageConfig, deviceConfig)
- def configure(self, imageConfig, _):
+ def configure(self, vmConfig, imageConfig, _):
"""Config actions common to all unix-like domains."""
-
- def get_cfg(name, default = None):
- return sxp.child_value(imageConfig, name, default)
-
- self.kernel = get_cfg("kernel")
- self.cmdline = ""
- ip = get_cfg("ip")
- if ip:
- self.cmdline += " ip=" + ip
- root = get_cfg("root")
- if root:
- self.cmdline += " root=" + root
- args = get_cfg("args")
- if args:
- self.cmdline += " " + args
- self.ramdisk = get_cfg("ramdisk", '')
-
+ self.kernel = vmConfig['kernel_kernel']
+ self.cmdline = vmConfig['kernel_args']
+ self.ramdisk = vmConfig['kernel_initrd']
self.vm.storeVm(("image/ostype", self.ostype),
("image/kernel", self.kernel),
("image/cmdline", self.cmdline),
ostype = "linux"
- def configure(self, imageConfig, deviceConfig):
- LinuxImageHandler.configure(self, imageConfig, deviceConfig)
+ def configure(self, vmConfig, imageConfig, deviceConfig):
+ LinuxImageHandler.configure(self, vmConfig, imageConfig, deviceConfig)
self.imageConfig = imageConfig
def buildDomain(self):
class HVMImageHandler(ImageHandler):
- def __init__(self, vm, imageConfig, deviceConfig):
- ImageHandler.__init__(self, vm, imageConfig, deviceConfig)
+ def __init__(self, vm, vmConfig, imageConfig, deviceConfig):
+ ImageHandler.__init__(self, vm, vmConfig, imageConfig, deviceConfig)
self.shutdownWatch = None
- def configure(self, imageConfig, deviceConfig):
- ImageHandler.configure(self, imageConfig, deviceConfig)
+ def configure(self, vmConfig, imageConfig, deviceConfig):
+ ImageHandler.configure(self, vmConfig, imageConfig, deviceConfig)
info = xc.xeninfo()
- if not 'hvm' in info['xen_caps']:
+ if 'hvm' not in info['xen_caps']:
raise VmError("HVM guest support is unavailable: is VT/AMD-V "
"supported by your CPU and enabled in your BIOS?")
self.dmargs = self.parseDeviceModelArgs(imageConfig, deviceConfig)
- self.device_model = sxp.child_value(imageConfig, 'device_model')
+ self.device_model = imageConfig['hvm'].get('device_model')
if not self.device_model:
raise VmError("hvm: missing device model")
- self.display = sxp.child_value(imageConfig, 'display')
- self.xauthority = sxp.child_value(imageConfig, 'xauthority')
- self.vncconsole = sxp.child_value(imageConfig, 'vncconsole')
+
+ self.display = imageConfig['hvm'].get('display')
+ self.xauthority = imageConfig['hvm'].get('xauthority')
+ self.vncconsole = imageConfig['hvm'].get('vncconsole')
self.vm.storeVm(("image/dmargs", " ".join(self.dmargs)),
("image/device-model", self.device_model),
self.dmargs += self.configVNC(imageConfig)
- self.pae = int(sxp.child_value(imageConfig, 'pae', 1))
- self.acpi = int(sxp.child_value(imageConfig, 'acpi', 1))
- self.apic = int(sxp.child_value(imageConfig, 'apic', 1))
+ self.pae = imageConfig['hvm'].get('pae', 0)
+ self.acpi = imageConfig['hvm'].get('acpi', 0)
+ self.apic = imageConfig['hvm'].get('apic', 0)
def buildDomain(self):
store_evtchn = self.vm.getStorePort()
'localtime', 'serial', 'stdvga', 'isa', 'vcpus',
'acpi', 'usb', 'usbdevice', 'keymap' ]
ret = []
+ hvmDeviceConfig = imageConfig['hvm']['devices']
+
for a in dmargs:
- v = sxp.child_value(imageConfig, a)
+ v = hvmDeviceConfig.get(a)
+ if a == 'vcpus':
+ v = hvmDeviceConfig.get('vcpus_number')
# python doesn't allow '-' in variable names
if a == 'stdvga': a = 'std-vga'
ret.append("-%s" % a)
ret.append("%s" % v)
- if a in ['fda', 'fdb' ]:
+ if a in ['fda', 'fdb']:
if v:
if not os.path.isabs(v):
raise VmError("Floppy file %s does not exist." % v)
# Handle disk/network related options
mac = None
- ret = ret + ["-domain-name", "%s" % self.vm.info['name']]
+ ret = ret + ["-domain-name", str(self.vm.info['name_label'])]
nics = 0
- for (name, info) in deviceConfig:
- if name == 'vbd':
- uname = sxp.child_value(info, 'uname')
+
+ for devuuid, (devtype, devinfo) in deviceConfig.items():
+ if devtype == 'vbd':
+ uname = devinfo['uname']
if uname is not None and 'file:' in uname:
(_, vbdparam) = string.split(uname, ':', 1)
if not os.path.isfile(vbdparam):
raise VmError('Disk image does not exist: %s' %
vbdparam)
- if name == 'vif':
- type = sxp.child_value(info, 'type')
- if type != 'ioemu':
+ if devtype == 'vif':
+ dtype = devinfo.get('type', 'ioemu')
+ if dtype != 'ioemu':
continue
nics += 1
- mac = sxp.child_value(info, 'mac')
+ mac = devinfo.get('mac')
if mac == None:
mac = randomMAC()
- bridge = sxp.child_value(info, 'bridge', 'xenbr0')
- model = sxp.child_value(info, 'model', 'rtl8139')
+ bridge = devinfo.get('bridge', 'xenbr0')
+ model = devinfo.get('model', 'rtl8139')
ret.append("-net")
ret.append("nic,vlan=%d,macaddr=%s,model=%s" %
(nics, mac, model))
ret.append("tap,vlan=%d,bridge=%s" % (nics, bridge))
return ret
- def configVNC(self, config):
+ def configVNC(self, imageConfig):
# Handle graphics library related options
- vnc = sxp.child_value(config, 'vnc')
- sdl = sxp.child_value(config, 'sdl')
+ vnc = imageConfig.get('vnc')
+ sdl = imageConfig.get('sdl')
ret = []
- nographic = sxp.child_value(config, 'nographic')
+ nographic = imageConfig.get('nographic')
# get password from VM config (if password omitted, None)
- vncpasswd_vmconfig = sxp.child_value(config, 'vncpasswd')
+ vncpasswd_vmconfig = imageConfig.get('vncpasswd')
if nographic:
ret.append('-nographic')
return ret
if vnc:
- vncdisplay = int(sxp.child_value(config, 'vncdisplay',
- self.vm.getDomid()))
+ vncdisplay = imageConfig.get('vncdisplay',
+ int(self.vm.getDomid()))
+ vncunused = imageConfig.get('vncunused')
- vncunused = sxp.child_value(config, 'vncunused')
if vncunused:
ret += ['-vncunused']
else:
ret += ['-vnc', '%d' % vncdisplay]
- vnclisten = sxp.child_value(config, 'vnclisten')
+ vnclisten = imageConfig.get('vnclisten')
+
if not(vnclisten):
vnclisten = (xen.xend.XendRoot.instance().
get_vnclisten_address())
if self.vncconsole:
args = args + ([ "-vncviewer" ])
log.info("spawning device models: %s %s", self.device_model, args)
+ # keep track of pid and spawned options to kill it later
self.pid = os.spawnve(os.P_NOWAIT, self.device_model, args, env)
log.info("device model pid: %d", self.pid)
def destroy(self):
- self.unregister_shutdown_watch();
+ self.unregister_shutdown_watch()
if not self.pid:
return
- os.kill(self.pid, signal.SIGKILL)
- os.waitpid(self.pid, 0)
+ try:
+ os.kill(self.pid, signal.SIGKILL)
+ os.waitpid(self.pid, 0)
+ except OSError, e:
+ log.warning("Unable to kill device model (pid: %d)" % self.pid)
+
self.pid = 0
def register_shutdown_watch(self):
""" add xen store watch on control/shutdown """
- self.shutdownWatch = xswatch(self.vm.dompath + "/control/shutdown", \
- self.hvm_shutdown)
+ self.shutdownWatch = xswatch(self.vm.dompath + "/control/shutdown",
+ self.hvm_shutdown)
log.debug("hvm shutdown watch registered")
def unregister_shutdown_watch(self):
@param image config
@return ImageHandler subclass or None
"""
- type = sxp.name(image)
- if type is None:
+ image_type = image['type']
+ if image_type is None:
raise VmError('missing image type')
try:
- return _handlers[arch.type][type]
+ return _handlers[arch.type][image_type]
except KeyError:
- raise VmError('unknown image type: ' + type)
+ raise VmError('unknown image type: ' + image_type)
#============================================================================
from threading import Event
+import types
from xen.xend import sxp
from xen.xend.XendError import VmError
import xen.xend.XendDomain
xd = xen.xend.XendDomain.instance()
- backdom_name = sxp.child_value(config, 'backend')
+ backdom_name = config.get('backend')
if backdom_name is None:
backdom = xen.xend.XendDomain.DOM0_ID
else:
configDict = self.getDeviceConfiguration(devid)
sxpr = [self.deviceClass]
for key, val in configDict.items():
- if type(val) == type(list()):
+ if isinstance(val, (types.ListType, types.TupleType)):
for v in val:
sxpr.append([key, v])
else:
import xen.xend.XendDomain
xd = xen.xend.XendDomain.instance()
- backdom_name = sxp.child_value(config, 'backend')
+ backdom_name = config.get('backend')
if backdom_name:
backdom = xd.domain_lookup_nr(backdom_name)
else:
from xen.util import blkif
from xen.util import security
-from xen.xend import sxp
from xen.xend.XendError import VmError
from xen.xend.server.DevController import DevController
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
- uname = sxp.child_value(config, 'uname', '')
- dev = sxp.child_value(config, 'dev', '')
-
+ uname = config.get('uname', '')
+ dev = config.get('dev', '')
+
if 'ioemu:' in dev:
(_, dev) = string.split(dev, ':', 1)
try:
except ValueError:
(typ, params) = ("", "")
- mode = sxp.child_value(config, 'mode', 'r')
+ mode = config.get('mode', 'r')
if mode not in ('r', 'w', 'w!'):
raise VmError('Invalid mode')
- back = { 'dev' : dev,
- 'type' : typ,
- 'params' : params,
- 'mode' : mode
- }
+ back = {'dev' : dev,
+ 'type' : typ,
+ 'params' : params,
+ 'mode' : mode,
+ }
- uuid = sxp.child_value(config, 'uuid')
+ uuid = config.get('uuid')
if uuid:
back['uuid'] = uuid
import xen.lowlevel.xc
-from xen.xend import sxp
from xen.xend.XendError import VmError
from xen.xend.server.DevController import DevController
def __init__(self, vm):
DevController.__init__(self, vm)
-
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
def get_param(field):
try:
- val = sxp.child_value(config, field)
+ val = config.get(field)
if not val:
raise VmError('ioports: Missing %s config setting' % field)
def get_param(field):
try:
- val = sxp.child_value(config, field)
+ val = config.get(field)
if not val:
raise VmError('irq: Missing %s config setting' % field)
import random
import re
-from xen.xend import sxp
from xen.xend import XendRoot
from xen.xend.server.DevController import DevController
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
- def _get_config_ipaddr(config):
- val = []
- for ipaddr in sxp.children(config, elt='ip'):
- val.append(sxp.child0(ipaddr))
- return val
-
script = os.path.join(xroot.network_script_dir,
- sxp.child_value(config, 'script',
- xroot.get_vif_script()))
- typ = sxp.child_value(config, 'type')
- bridge = sxp.child_value(config, 'bridge')
- mac = sxp.child_value(config, 'mac')
- vifname = sxp.child_value(config, 'vifname')
- rate = sxp.child_value(config, 'rate')
- uuid = sxp.child_value(config, 'uuid')
- ipaddr = _get_config_ipaddr(config)
+ config.get('script', xroot.get_vif_script()))
+ typ = config.get('type')
+ bridge = config.get('bridge')
+ mac = config.get('mac')
+ vifname = config.get('vifname')
+ rate = config.get('rate')
+ uuid = config.get('uuid')
+ ipaddr = config.get('ip')
devid = self.allocateDeviceID()
def getDeviceDetails(self, config):
"""@see DevController.getDeviceDetails"""
- #log.debug('pci config='+sxp.to_string(config))
-
- def get_param(config, field, default=None):
+ def parse_hex(val):
try:
- val = sxp.child_value(config, field)
-
- if not val:
- if default==None:
- raise VmError('pci: Missing %s config setting' % field)
- else:
- return default
-
if isinstance(val, types.StringTypes):
return int(val, 16)
else:
return val
- except:
- if default==None:
- raise VmError('pci: Invalid config setting %s: %s' %
- (field, val))
- else:
- return default
-
- back = {}
-
- val = sxp.child_value(config, 'dev')
- if isinstance(val, (types.ListType, types.TupleType)):
- pcidevid = 0
- for dev_config in sxp.children(config, 'dev'):
- domain = get_param(dev_config, 'domain', 0)
- bus = get_param(dev_config,'bus')
- slot = get_param(dev_config,'slot')
- func = get_param(dev_config,'func')
-
- self.setupDevice(domain, bus, slot, func)
-
- back['dev-%i' % pcidevid]="%04x:%02x:%02x.%02x"% \
- (domain, bus, slot, func)
- pcidevid+=1
+ except ValueError:
+ return None
- back['num_devs']=str(pcidevid)
-
- else:
- # Xen 2.0 configuration compatibility
- domain = get_param(config, 'domain', 0)
- bus = get_param(config, 'bus')
- slot = get_param(config, 'dev')
- func = get_param(config, 'func')
-
+ back = {}
+ pcidevid = 0
+ for pci_config in config.get('devs', []):
+ domain = parse_hex(pci_config.get('domain', 0))
+ bus = parse_hex(pci_config.get('bus', 0))
+ slot = parse_hex(pci_config.get('slot', 0))
+ func = parse_hex(pci_config.get('func', 0))
self.setupDevice(domain, bus, slot, func)
+ back['dev-%i' % pcidevid] = "%04x:%02x:%02x.%02x" % \
+ (domain, bus, slot, func)
+ pcidevid += 1
- back['dev-0']="%04x:%02x:%02x.%02x"%(domain, bus, slot, func)
- back['num_devs']=str(1)
-
+ back['num_devs']=str(pcidevid)
+ back['uuid'] = config.get('uuid','')
return (0, back, {})
def getDeviceConfiguration(self, devid):
'slot': '0x%(slot)s' % pci_dev_info,
'func': '0x%(func)s' % pci_dev_info})
- result['dev'] = pci_devs
+ result['devs'] = pci_devs
+ result['uuid'] = self.readBackend(devid, 'uuid')
return result
def configuration(self, devid):
sxpr = [self.deviceClass]
# remove devs
- devs = configDict.pop('dev', [])
+ devs = configDict.pop('devs', [])
+
for dev in devs:
dev_sxpr = ['dev']
for dev_item in dev.items():
self.device = device
self.subvendor = subvendor
self.subdevice = subdevice
- self.domain = domain
- self.bus = bus
- self.slot = slot
- self.func = func
+ self.domain = domain
+ self.bus = bus
+ self.slot = slot
+ self.func = func
self.devid = "%04x:%04x:%04x:%04x" % (vendor, device, subvendor, subdevice)
- self.pciid = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
+ self.pciid = "%04x:%02x:%02x.%01x" % (domain, bus, slot, func)
+ self.quirks = self.__getQuirksByID()
- self.quirks = self.__getQuirksByID( )
-
- self.__sendQuirks( )
- self.__sendPermDevs( )
+ self.__sendQuirks()
+ self.__sendPermDevs()
def __matchPCIdev( self, list ):
ret = False
if list == None:
return False
for id in list:
- if id.startswith( self.devid[:9] ): # id's vendor and device ID match
+ if id.startswith(self.devid[:9]): # id's vendor and device ID match
skey = id.split(':')
size = len(skey)
if (size == 2): # subvendor/subdevice not suplied
break
elif (size == 4): # check subvendor/subdevice
# check subvendor
- subven = '%04x' % self.subvendor
+ subven = '%04x' % self.subvendor
if ((skey[2] != 'FFFF') and
(skey[2] != 'ffff') and
(skey[2] != subven)):
continue
# check subdevice
- subdev = '%04x' % self.subdevice
+ subdev = '%04x' % self.subdevice
if ((skey[3] != 'FFFF') and
(skey[3] != 'ffff') and
(skey[3] != subdev)):
self.slot, self.func, quirk) )
f.close()
except Exception, e:
- raise VmError("pci: failed to open/write/close quirks sysfs " + \
- "node - " + str(e))
+ raise VmError("pci: failed to open/write/close quirks " +
+ "sysfs node - " + str(e))
def __devIsUnconstrained( self ):
if os.path.exists(PERMISSIVE_CONFIG_FILE):
devices = child_at(child(pci_perm_dev_config, 'unconstrained_dev_ids'),0)
if self.__matchPCIdev( devices ):
- log.debug("Permissive mode enabled for PCI device [%s]" % self.devid)
+ log.debug("Permissive mode enabled for PCI device [%s]" %
+ self.devid)
return True
- log.debug("Permissive mode NOT enabled for PCI device [%s]" % self.devid)
+ log.debug("Permissive mode NOT enabled for PCI device [%s]" %
+ self.devid)
return False
def __sendPermDevs(self):
if self.__devIsUnconstrained( ):
- log.debug("Unconstrained device: %04x:%02x:%02x.%1x" % (self.domain,
- self.bus, self.slot, self.func))
+ log.debug("Unconstrained device: %04x:%02x:%02x.%1x" %
+ (self.domain, self.bus, self.slot, self.func))
try:
f = file(PERMISSIVE_SYSFS_NODE ,"w")
f.write( "%04x:%02x:%02x.%1x" % (self.domain, self.bus,
- self.slot, self.func) )
+ self.slot, self.func))
f.close()
except Exception, e:
- raise VmError("pci: failed to open/write/close permissive " + \
- "sysfs node: " + str(e))
+ raise VmError("pci: failed to open/write/close permissive " +
+ "sysfs node: " + str(e))
def testNetif(self):
controller = self.controllerInstance(netif.NetifController)
- self.assertNetif(controller.getDeviceDetails(['vif']), None)
+ self.assertNetif(controller.getDeviceDetails({}), None)
self.assertNetif(
- controller.getDeviceDetails(
- ['vif', ['mac', 'aa:bb:cc:dd:ee:ff']]),
+ controller.getDeviceDetails({'mac': 'aa:bb:cc:dd:ee:ff'}),
'aa:bb:cc:dd:ee:ff')
+
def assertNetif(self, results, expectedMac):
(devid, backdets, frontdets) = results
# Copyright (C) 2005 XenSource Ltd
#============================================================================
-"""Support for virtual TPM interfaces.
-"""
+"""Support for virtual TPM interfaces."""
-from xen.xend import sxp
from xen.xend import XendRoot
from xen.xend.XendLogging import log
from xen.xend.XendError import XendError
"""@see DevController.getDeviceDetails"""
devid = self.allocateDeviceID()
- inst = int(sxp.child_value(config, 'pref_instance', '-1'))
+ inst = int(config.get('pref_instance', -1))
if inst == -1:
- inst = int(sxp.child_value(config, 'instance' , '0'))
+ inst = int(config.get('instance', 0))
- typ = sxp.child_value(config, 'type')
- uuid = sxp.child_value(config, 'uuid')
+ typ = config.get('type')
+ uuid = config.get('uuid')
log.info("The domain has a TPM with pref. instance %d and devid %d.",
inst, devid)
return {
'domid' : get_info('domid', str, ''),
'name' : get_info('name', str, '??'),
- 'mem' : get_info('memory_dynamic_max', int, 0),
- 'vcpus' : get_info('online_vcpus', int, 0),
+ 'mem' : get_info('memory_dynamic_min', int, 0),
+ 'vcpus' : get_info('vcpus', int, 0),
'state' : get_info('state', str, ''),
'cpu_time' : get_info('cpu_time', float, 0),
'up_time' : get_info('up_time', float, -1),